package file

import (
	"common/api"
	"common/utils"
	"encoding/json"
	"github.com/gin-gonic/gin"
	"github.com/mitchellh/mapstructure"
	"io"
	"os"
	"path/filepath"
	"time"
)

type FileInfo struct {
	Ext       string `json:"ext"`
	Md5       string `json:"md5"`
	FName     string `json:"fname"`
	Size      int64  `json:"size"`
	UpTime    string `json:"uptime"`
	FileId    string `json:"fileId"`
	ObsFileId string `json:"obsFileId"`
	ObsUrl    string `json:"obsUrl"`
}

func Struct2Map(Struct any) map[string]any {
	jsonBytes, _ := json.Marshal(Struct)
	var mapResult gin.H
	json.Unmarshal(jsonBytes, &mapResult)
	return mapResult
}

func GetFileInfoById(fileId string) FileInfo {
	var FileInfoIns FileInfo
	MongoClient, _ := utils.NewMongoClient()
	filter := utils.NewFilter().EQ("fileId", fileId)
	result := MongoClient.FindOne("fileStorage", filter)

	if len(result) != 0 {
		mapstructure.Decode(result, &FileInfoIns)
		return FileInfoIns
	} else {
		return FileInfoIns
	}
}

func GetFileInfo(filePath string) FileInfo {
	file, _ := os.Open(filePath)
	defer file.Close()
	bytes, _ := io.ReadAll(file)
	fileMD5 := utils.Md5(bytes)
	var FileInfoIns FileInfo

	//判断是数据库里面是否有该文件
	MongoClient, _ := utils.NewMongoClient()

	filter := utils.NewFilter().EQ("md5", fileMD5)
	result := MongoClient.FindOne("fileStorage", filter)

	if len(result) != 0 {
		mapstructure.Decode(result, &FileInfoIns)
		return FileInfoIns
	}

	fileInfo, _ := os.Stat(filePath)
	fileSize := fileInfo.Size()
	fileObsId, _ := api.ObsUpload(filePath)
	fileObsUri := api.ObsUrl(fileObsId)
	FileInfoIns.Ext = filepath.Ext(filePath)
	FileInfoIns.Md5 = fileMD5
	FileInfoIns.FName = filepath.Base(filePath)
	FileInfoIns.Size = fileSize
	FileInfoIns.UpTime = time.Now().Format("2006-01-02 03:04:05")
	FileInfoIns.FileId = utils.GetFileId()
	FileInfoIns.ObsFileId = fileObsId
	FileInfoIns.ObsUrl = fileObsUri
	MongoClient.InsertOne("fileStorage", Struct2Map(FileInfoIns))

	return FileInfoIns
}

func UploadViews(ctx *gin.Context) {
	file, _ := ctx.FormFile("file")

	if file == nil {
		utils.ResponseFail(ctx, "not file receive")
		return
	}
	filePath := utils.GetFilePath(file.Filename)
	err := ctx.SaveUploadedFile(file, filePath)
	if err != nil {
		utils.ResponseFail(ctx, err.Error())
		return
	}

	//删除文件夹
	defer func(name string) {
		err := os.Remove(name)
		if err != nil {
		}
	}(filepath.Dir(filePath))

	//删除文件
	defer func(name string) {
		err := os.Remove(name)
		if err != nil {
		}
	}(filePath)

	fileInfo := GetFileInfo(filePath)
	utils.ResponseOK(ctx, gin.H{"fileId": fileInfo.FileId})
}

func DownloadViews(ctx *gin.Context) {
	fileId := ctx.Query("fileId")

	//接收参数问题
	if len(fileId) == 0 {
		utils.ResponseFail(ctx, "not fileId receive")
		return
	}

	//数据库不存在问题
	fileInfo := GetFileInfoById(fileId)
	if len(fileInfo.Md5) == 0 {
		utils.ResponseFail(ctx, "fileId not exists")
		return
	}

	filePath := utils.GetFilePath(fileInfo.FName)

	//删除文件夹
	defer func(name string) {
		err := os.Remove(name)
		if err != nil {
		}
	}(filepath.Dir(filePath))

	//删除文件
	defer func(name string) {
		err := os.Remove(name)
		if err != nil {
		}
	}(filePath)

	err := api.ObsDownload(fileInfo.ObsFileId, filePath)

	if err != nil {
		utils.ResponseFail(ctx, "fileId download failed")
		return
	}

	ctx.FileAttachment(filePath, filepath.Base(filePath))
}

func FileInfoViews(ctx *gin.Context) {
	fileId := ctx.Query("fileId")

	if len(fileId) == 0 {
		utils.ResponseFail(ctx, "not fileId receive")
	}

	fileInfo := GetFileInfoById(fileId)
	utils.ResponseOK(ctx, fileInfo)
}
